/*
** dsp.c
**
** This module contains function to display Ftool model entities.
**
** TeCGraf - Grupo de Tecnologia em Computacao Grafica - PUC-Rio.
**
** Created on 16 Jan 92 by LFMartha.
**
** Modified on 17 Mar 94 by LFMartha.
**      When implemented display of support reactions.
**
** Modified on 27-Jul-94 by LFMartha.
**      Changed function DspVertLibAllEdges such that it
**      return a false (0) status for a disjoint vertex.
**
** Modified on 08-Feb-95 by LFMartha.
**      This modification was done to display an entire model, 
**      with no drawing of hidden entities in back color and no 
**      drawing each vertex only once.
**      Created local function DspRawEdge, that displays an
**      edge with no attempt to display its its hidden attributes
**      in back color or to display its end vertices.
**      Created local function DspRawVertex, that displays a
**      vertex with no attempt to display its its hidden attributes
**      in back color.
**      Modified DspModel such that it calls DspRawEdge for
**      each edge and calls DspRawVertex for each vertex.
**
** Modified on 13-Apr-95 by LFMartha.
**      Modified function DspRotLibVertexAttrib such that it 
**      returns a true vertex rotation liberation flag in all the
**      cases where all the members around the given vertex have
**      hinges.  Before, if there were any support that constrained
**      displacements at that vertex, it returned a false flag in
**      any case.
**      Replaced DspVertLibAllEdges by existing RotLibVertLibAllEdges
**      which was doing exactly the same thing.
**
** Modified on 25-Jan-96 by LFMartha.
**      Eliminated commented out code from previous modifications.
**
** Modified on 21-Feb-98 by LFMartha.
**      Changed mark size parameter from 0.7 to 0.4.
**      Changed mark size type from GRA_STAR to GRA_CIRCLE.
**      Reduced size of rot lib circle and made sizes of vertex 
**      and edge rot lib circles different.
**      Reduced size of supports from 0.035 to 0.025 of window size.
**
** Modified on 03-May-98 by LFMartha.
**      When added maximum local moment parameter in function DspResEffDiagr.
**
** Modified on 01-Oct-98 by LFMartha.
**      Fixed display of prescribed displacement arrows.
**      Before it was displaying an arrow for non-prescribed
**      displacement if the corresponding displacement had a
**      non-null value and another displacement at the node
**      was prescribed.
**
** Modified on 01-Feb-99 by LFMartha.
**      Version 2.04: Changed grid such that grid spacing may have different
**      step sizes in X and Y directions.
**
** Modified on 15-Apr-99 by LFMartha.
**      Changed mark type of vertices from GRA_CIRCLE to GRA_DIAMOND.
**      Changed vertex mark size from 0.4 to 0.5.
**      Changed star mark size from 1.0 to 0.9.
**      Changed plus mark size from 1.0 to 1.1.
**
** Modified on 17-Feb-2000 by LFMartha.
**      Version 2.06: Created parameter units.
**      Created spring supports.
**      Created temperature variation loading.
**      Created "load with results" visibility flag.
**      Replaced local function DspWnSize by new global 
**      function DspUtlWnSize.
**      Created load and reaction values visibility flags: added
**      option to display load and reaction values.
**      Added text size argument to load, reaction, etc. display functions.
**      Created functions DspSpringKxVal, DspSpringKyVal, and
**      DspSpringKzVal to display spring stiffness values.
**
** Modified on 02-Jun-2000 by LFMartha.
**     Version 2.08:
**     Added call to function EdtChkEmptyModel for checking for empty
**     model.
**
** Modified on 15-Jan-2001 by LFMartha.
**     Version 2.09:
**     Created member displacement constraints: edge line width is set
**     accordingly (no constraint ==> width = 1; axial constraint ==> width =3;
**     rigid constraint ==> width = 7).
**     Created member end moments loading: created function DspMEndMomLoad.
**     Deleted functions DspEdge and DspVertex and renamed local 
**     functions DspRawEdge to DspEdge and DspRawVertex to DspVertex.
**     Renamed function DspRlibRawVertex to DspRlibVertex.
**     Created global variables to hold display sizes.
**     Deleted size arguments in display functions.
**     Introduced concept of offset distance in axial direction to 
**     display loads and internal force diagrams.  The offset is caused
**     by hinges and plate box supports.  Display of member loads and 
**     internal force diagrams are now displayed within the offset 
**     positions (previously they were displayed from vertex to vertex).
**     Added offset parameters to functions DspResEffDiagr,
**     DspResValue, DspSupPrescrDispl, and DspSupReact.
**     Deleted local function DspRotLibVertexAttrib.  Now function
**     DspUtlVertRotLibAllEdges is used.
**     Modified display of prescribed displacement support such that
**     each support constraint is displayed separetely: created local 
**     function DspSupPrDisplAttrib.
**
** Modified on 15-Oct-2001 by LFMartha.
**     Version 2.10:
**     When created influence line response mode.
**     Created function DspResILDiagr.
**     
** Modified on 14-Feb-2002 by LFMartha.
**   Version 2.11: 
**     Changed display of result values at a homegenous vertex
**     (one or two adjacent and aligned edges) with equal
**     values at adjacent edges.  In such cases, only one value
**     is displayed centered at the vertex.
**     For this, two auxiliary functions were created:
**     DspUtlChkHomogVert and DspUtlChkEqualResVal (see dsputl.c).
**     Also, added end values text alignment parameters in functions
**     DspResEffDiagr and DspResILDiagr.
**
*/

#define _DSP_ATT_C

#include <math.h>

#include "hed.h"

#include "clt.h"
#include "edit.h"
#include "dsp.h"
#include "gra.h"
#include "color.h"


#if 0
/* Display global variables
 */
double   dsp_sizew;        /* window characteristic size */
double   dsp_sizear;       /* arrow characteristic size */
double   dsp_sizevrl;      /* vertex hinge characteristic size */
double   dsp_sizeerl;      /* edge hinge characteristic size */
double   dsp_sizergth;     /* rigid edge characteristic thickness */
double   dsp_sizesup;      /* support characteristic size */
double   dsp_sizeplt;      /* support box (plate) characteristic size */
double   dsp_sizenf;       /* nodal force characteristic size */
double   dsp_sizemom;      /* moment characteristic size */
double   dsp_sizel;        /* member load characteristic size */
double   dsp_sizetxt;      /* text characteristic size */
#endif

/*  Internal Functions:  */
static void DspEdge (HedEdge *edge);
static int DspSupAttrib( Tnode *node, int *type, double *angle );
static int DspSupSpringAttrib( Tnode *node, int *typex, double *angx,
                                            int *typey, double *angy,
                                            int *typez, double *angz );
static int DspSupPrDisplAttrib( Tnode *node, 
                                int *typex, double *angx, double *offsetx,
                                int *typey, double *angy, double *offsety,
                                int *typez, double *angz );
static void DspVertex (HedVertex *vertex);




/*
** Get the support attributes to display a support with spring
*/
static int DspSupSpringAttrib( Tnode *node, int *typex, double *angx,
                                            int *typey, double *angy,
                                            int *typez, double *angz )
{
 char sc[3];

 sc[0] = node->sup[0];
 sc[1] = node->sup[1];
 sc[2] = node->sup[2];

 if     ( sc[0] == '2' )
 {
  *typex = 6;
  *angx = - PI/2.0;
 }
 else if( sc[0] == '1' )
 {
  *typex = 1;
  *angx = - PI/2.0;
 }
 else
 {
  *typex = 0;
  *angx = 0.0;
 }

 if     ( sc[1] == '2' )
 {
  *typey = 6;
  *angy = 0.0;
 }
 else if( sc[1] == '1' )
 {
  if( sc[0] == '1' )
  {
   *typex = 2;
   *angx = 0.0;
   *typey = 0;
   *angy = 0.0;
  }
  else
  {
   *typey = 1;
   *angy = 0.0;
  }
 }
 else
 {
  *typey = 0;
  *angy = 0.0;
 }

 if     ( sc[2] == '2' )
 {
  *typez = 7;
  *angz = 0.0;
 }
 else if( sc[2] == '1' )
 {
  if( sc[0] == '1' )
  {
   *typex = 4;
   *angx = - PI/2.0;
   *typez = 0;
   *angz = 0.0;
  }
  else if( sc[1] == '1' )
  {
   *typey = 4;
   *angy = 0.0;
   *typez = 0;
   *angz = 0.0;
  }
  else
  {
   *typez = 5;
   *angz = 0.0;
  }
 }
 else
 {
  *typez = 0;
  *angz = 0.0;
 }

 return( 1 );
}


/*
** Get the support attributes to display a support with prescribed displac.
*/
static int DspSupPrDisplAttrib( Tnode *node, 
                                int *typex, double *angx, double *offsetx,
                                int *typey, double *angy, double *offsety,
                                int *typez, double *angz )
{
 *offsetx = 0.0;
 *offsety = 0.0;

 if( node->sup[0] == '1' )
 {
  *typex = 1;
  *angx = - PI/2.0;
 }
 else
 {
  *typex = 0;
  *angx = 0.0;
 }

 if( node->sup[1] == '1' )
 {
  *typey = 1;
  *angy = 0.0;
 }
 else
 {
  *typey = 0;
  *angy = 0.0;
 }

 if( node->sup[2] == '1' )
 {
  *typez = 5;
  *angz = 0.0;
  if( node->sup[0] == '1' )
  {
   *offsetx = - dsp_sizeplt * 0.5;
  }
  if( node->sup[1] == '1' )
  {
   *offsety = - dsp_sizeplt * 0.5;
  }
 }
 else
 {
  *typez = 0;
  *angz = 0.0;
 }

 if( *typex || *typey || *typez )
  return( 1 );

 return( 0 );
}



/*
** Display a vertex.
*/
static void DspVertex (HedVertex *vertex)
{
 Tnode  *node;
 Nforc  nf;
 int    select;
 int    prescdispl;
 int    typesup;
 int    typex;
 int    typey;
 int    typez;
 int    typerl;
 double angle;
 double angx;
 double angy;
 double angz;
 double offsetx;
 double offsety;
 Tpoint pt;
 Tnodaldisp ndisp;
 Tnetforce  react;

 if (vertex == NULL)
  return;

 node = vertex->u_atrib;
 if( node )
 {
  nf = node->force;
  select = node->select;
  prescdispl = node->prescdispl;
 }
 else
 {
  nf = 0L;
  select = 0;
  prescdispl = 0;
 }

 typerl = DspUtlVertRotLibAllEdges ( vertex );
 DspRlibVertex ( typerl, vertex, Color.domain );

 if ( (node) && (Ftool.vis.support == ON) )
 {
  if( FtoolHasSpringSupport(node->sup) )
  {
   if( DspSupSpringAttrib(node, &typex, &angx, &typey, &angy, &typez, &angz) )
   {
    if( (typex) && ((typex!=6) || (node->nsprg.kdx)) )
    {
     DspSupport( typex, (Tpoint *)&vertex->vcoord, angx, Color.supp );
     if( (Ftool.vis.loadval == ON) && (typex == 6) && 
	 ( (Ftool.stage == PRE) || 
	  ((Ftool.stage == POS) && (Ftool.vis.loadwresp == ON)) ) )
      DspSpringKxVal( (Tpoint *)&vertex->vcoord, node->nsprg.kdx, Color.supp );
    }
    if( (typey) && ((typey!=6) || (node->nsprg.kdy)) )
    {
     DspSupport( typey, (Tpoint *)&vertex->vcoord, angy, Color.supp );
     if( (Ftool.vis.loadval == ON) && (typey == 6) && 
	 ( (Ftool.stage == PRE) || 
	  ((Ftool.stage == POS) && (Ftool.vis.loadwresp == ON)) ) )
      DspSpringKyVal( (Tpoint *)&vertex->vcoord, node->nsprg.kdy, Color.supp );
    }
    if( (typez) && ((typez!=7) || (node->nsprg.krz)) )
    {
     DspSupport( typez, (Tpoint *)&vertex->vcoord, angz, Color.supp );
     if( (Ftool.vis.loadval == ON) && (typez == 7) && 
	 ( (Ftool.stage == PRE) || 
	  ((Ftool.stage == POS) && (Ftool.vis.loadwresp == ON)) ) )
      DspSpringKzVal( (Tpoint *)&vertex->vcoord, node->nsprg.krz, Color.supp );
    }
   }
  }
  else if( prescdispl )
  {
   if( DspSupPrDisplAttrib( node, &typex, &angx, &offsetx, 
				  &typey, &angy, &offsety, &typez, &angz) )
   {
    if( typex )
    {
     pt.x = vertex->vcoord.x + offsetx;
     pt.y = vertex->vcoord.y;
     DspSupport( typex, &pt, angx, Color.supp );
    }
    if( typey )
    {
     pt.x = vertex->vcoord.x;
     pt.y = vertex->vcoord.y + offsety;
     DspSupport( typey, &pt, angy, Color.supp );
    }
    if( typez )
    {
     pt.x = vertex->vcoord.x;
     pt.y = vertex->vcoord.y;
     DspSupport( typez, &pt, angz, Color.supp );
    }
   }
  }
  else if( DspSupAttrib( node, &typesup, &angle ) )
  {
   DspSupport(typesup, (Tpoint *)&vertex->vcoord, angle, Color.supp);
  }
 }

 GraSetMarkSize (0.5);
 GraSetMarkType (GRA_DIAMOND);
 if (select)
 {
  if (Color.mono)
  {
   GraSetMarkColor (Color.feedback);
   GraSetMarkSize (0.9);
   GraSetMarkType (GRA_STAR);
   GraPolyMark (1, (Tpoint *)&vertex->vcoord);
   GraSetMarkSize (0.4);
   GraSetMarkType (GRA_DIAMOND);
  }
  GraSetMarkColor (Color.feedback);
  GraPolyMark (1, (Tpoint *)&vertex->vcoord);
 }
 else
 {
  GraSetMarkColor (Color.vertex);
  GraPolyMark (1, (Tpoint *)&vertex->vcoord);
 }

 if( ((Ftool.stage == PRE) && (Ftool.vis.load == ON)) || 
     ((Ftool.stage == POS) && (Ftool.vis.loadwresp == ON) &&
                              (Ftool.resultmode == DIAGRAM)) )
 {
  if (nf)
  {
   DspLoadNod ( (Tpoint *)&vertex->vcoord, nf->fx, nf->fy, nf->mz, 
                 Color.nforc );
  }

  if( prescdispl )
  {
   if( DspSupPrDisplAttrib( node, &typex, &angx, &offsetx, 
				  &typey, &angy, &offsety, &typez, &angz) )
   {
    if (node->sup[0] == '1') ndisp.dx = node->ndisp.dx;
    else                     ndisp.dx = 0.0;
    if (node->sup[1] == '1') ndisp.dy = node->ndisp.dy;
    else                     ndisp.dy = 0.0;
    if (node->sup[2] == '1') ndisp.rz = node->ndisp.rz;
    else                     ndisp.rz = 0.0;

    DspSupPrescrDispl( (Tpoint *)&vertex->vcoord, ndisp.dx, ndisp.dy, ndisp.rz,
                        offsetx, offsety, Color.prescdisp );
   }
  }
 }

 if( (Ftool.stage == POS) && (Ftool.resultmode == DIAGRAM) && 
     (Ftool.vis.reactions == ON) )
 {
  if( ! FtoolIsFreeSupport( node->sup ) )
  {
   PosVertNetForce( vertex, &react );

   if (node->skewang == 0.0)
   {
    if (node->sup[0]=='0') react.fx = 0.0;
    if (node->sup[1]=='0') react.fy = 0.0;
   }
   if (node->sup[2]=='0') react.mz = 0.0;

   if( FtoolHasSpringSupport(node->sup) )
   {
    if( (node->sup[0]=='2') && (node->nsprg.kdx == 0.0) ) react.fx = 0.0;
    if( (node->sup[1]=='2') && (node->nsprg.kdy == 0.0) ) react.fy = 0.0;
    if( (node->sup[2]=='2') && (node->nsprg.krz == 0.0) ) react.mz = 0.0;
   }

   if( DspUtlChkPltSup( vertex ) )
   {
    offsetx = - dsp_sizeplt * 0.5;
    offsety = - dsp_sizeplt * 0.5;
   }
   else
   {
    offsetx = 0.0;
    offsety = 0.0;
   }

   DspSupReact ( (Tpoint *)&vertex->vcoord, react.fx, react.fy, react.mz, 
                  offsetx, offsety, Color.reaction );
  }
 }

 if ( (Ftool.stage == POS) && (Ftool.vis.nodnb == ON) )
 {
  char text[5];

  sprintf(text,"%d",node->id);
  DspResNodNb ( (Tpoint *)&vertex->vcoord, text, Color.nodenb );
 }
}


/*
** Display a line
*/
void DspLine (Tpoint *p, int color)
{
 GraSetLineColor (color);
 GraPolyLine (2, p);
}


/*
** Display the grid
*/
void DspGrid (void)
{
#if 0
 Tpoint  p;
 Twindow wn;
 double  hsize_mm, hsize_wc;
 double  vsize_mm, vsize_wc;
 double  density;

/* Get canvas horizontal size in milimeters and
 * window in world coordinates.
 */
 GraGetCanvasSizes( 0L, 0L, &hsize_mm, &vsize_mm );
 GraGetWindow( &wn.xmin, &wn.xmax, &wn.ymin, &wn.ymax );
 hsize_wc = wn.xmax - wn.xmin;
 vsize_wc = wn.ymax - wn.ymin;

/* Do not display grid if grid point spacing is less
 * then 2 milimeters.
 */
 density = Ftool.grid_stepx * (hsize_mm / hsize_wc);
 if( density < 2.0 )
  return;
 density = Ftool.grid_stepy * (vsize_mm / vsize_wc);
 if( density < 2.0 )
  return;

 p.x = p.y = 0.0;
 GraSetMarkColor (Color.grid);
 GraSetMarkType (GRA_PLUS);		/* (+) */
 GraSetMarkSize (1.1);
 GraPolyMark (1, &p);		/* mark origin */
 GraSetMarkType (GRA_POINT);		/* (.) */
 for (p.x = (int)(wn.xmin/Ftool.grid_stepx) * Ftool.grid_stepx;
      p.x <= (int)(wn.xmax/Ftool.grid_stepx)*Ftool.grid_stepx+Ftool.grid_stepx;
      p.x += Ftool.grid_stepx)
 {
  for (p.y = (int)(wn.ymin/Ftool.grid_stepy) * Ftool.grid_stepy;
       p.y <= (int)(wn.ymax/Ftool.grid_stepy)*Ftool.grid_stepy+Ftool.grid_stepy;
       p.y += Ftool.grid_stepy)
  {
   GraPolyMark (1, &p);
  }
 }
#else
 Tpoint  p;
 p.x = p.y = 0.0;
 GraSetMarkColor (Color.grid);
 GraSetMarkType (GRA_PLUS);		/* (+) */
 GraSetMarkSize (1.1);
 GraPolyMark (1, &p);		/* mark origin */
 GraGrid( 0.0, 0.0, Ftool.grid_stepx, Ftool.grid_stepy );
#endif
}


